package com.my.zl.console.service.online.impl;

import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.my.zl.common.dto.ReqDTO;
import com.my.zl.common.dto.advancedQuery.PageQueryDTO;
import com.my.zl.common.enums.resp.GlobalEnum;
import com.my.zl.common.exception.BizException;
import com.my.zl.common.utils.CopyUtil;
import com.my.zl.console.common.config.mybatis.MapString;
import com.my.zl.console.common.constant.AutocodeC;
import com.my.zl.console.dao.online.LoadTableDao;
import com.my.zl.console.dao.online.OnlineSqlMapper;
import com.my.zl.console.dao.online.ZlDatabaseInfoMapper;
import com.my.zl.console.dao.online.ZlDatabaseTableMapper;
import com.my.zl.console.dto.online.databaseTable.ReqDatabaseTableAddDTO;
import com.my.zl.console.dto.online.databaseTable.ReqDatabaseTableQueryDTO;
import com.my.zl.console.dto.online.databaseTable.ReqDatabaseTableSqlQueryDTO;
import com.my.zl.console.dto.online.databaseTable.ResDatabaseTableAddDTO;
import com.my.zl.console.dto.online.databaseTable.ResDatabaseTableQueryDTO;
import com.my.zl.console.dto.online.databaseTable.ResDatabaseTableSqlQueryDTO;
import com.my.zl.console.dto.online.databaseTable.ResDatabaseTableVO2;
import com.my.zl.console.entity.online.ZlDatabaseInfo;
import com.my.zl.console.entity.online.ZlDatabaseTable;
import com.my.zl.console.service.base.BaseManager;
import com.my.zl.console.service.online.IDatabaseInfoService;
import com.my.zl.console.service.online.IDatabaseTableService;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.ds.simple.SimpleDataSource;

/**
 * 数据库表字段
 * @author ZL
 */
@Service
public class DatabaseTableManager extends BaseManager implements IDatabaseTableService {
    private static Logger LOGGER = LoggerFactory.getLogger(DatabaseTableManager.class);
    
    @Autowired
    private ZlDatabaseTableMapper databaseTableMapper;
    @Autowired
    private IDatabaseInfoService databaseInfoService;
    @Autowired
    protected DataSource dynamicDataSource;
    @Autowired
    protected Map<String,LoadTableDao> loadTableDao;
    @Autowired
    protected OnlineSqlMapper onlineSqlMapper;
    

    @Override
    public ResDatabaseTableQueryDTO getDatabaseTableList(ReqDatabaseTableQueryDTO reqInfo) throws Exception{
        // TODO Auto-generated method stub
        ResDatabaseTableQueryDTO resDTO = new ResDatabaseTableQueryDTO();
        
        Map<String,Object> paramMap = new HashMap<>();
        paramMap = BeanUtil.beanToMap(reqInfo);
        
        List<ZlDatabaseTable> list = databaseTableMapper.selectColumnCodeList(paramMap);
        
        if(list!=null && list.size()>0){
            resDTO.setList(CopyUtil.copyList(list, ResDatabaseTableVO2.class));
        }
        
        return resDTO;
    }

    @Override
    public ResDatabaseTableAddDTO selectDatabaseTableCodes(ReqDTO<ReqDatabaseTableAddDTO> reqInfo)throws Exception {
        // TODO Auto-generated method stub
        ReqDatabaseTableAddDTO reqData = reqInfo.getReqData();
        ResDatabaseTableAddDTO resDTO = new ResDatabaseTableAddDTO();
        
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("databaseId", reqData.getDatabaseId());
        
        ZlDatabaseInfo databaseInfo = databaseInfoService.selectDatabaseInfo(reqData.getDatabaseId());
        
        
        List<String> tableCodes = reqData.getTableCodes();
        
        List<String> hasTableCodes =  new ArrayList<>();
        if("0".equals(reqData.getLoadType())){
            List<String> hasTableCodesList = databaseTableMapper.selectTableCodeList(paramMap);
            if(hasTableCodesList!=null && hasTableCodesList.size()>0){
                hasTableCodesList.stream().forEach(x->{
                    hasTableCodes.add(x.toUpperCase());
                });
            }
        }
        
        resDTO.setDatabaseType(databaseInfo.getDatabaseType());
        resDTO.setDatabaseId(databaseInfo.getDatabaseId());
        
        String cdskey = "dynamic-" + databaseInfo.getDatabaseId();
        try{
            if(StringUtils.isNotBlank(databaseInfo.getJdbcUrl()) && StringUtils.isNotBlank(databaseInfo.getJdbcLoginname())
                    && StringUtils.isNotBlank(databaseInfo.getJdbcPassword())){
                DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource)dynamicDataSource;
                if(!dynamicRoutingDataSource.getCurrentDataSources().containsKey(cdskey)){
                    SimpleDataSource dynamicDataSourceVO = new SimpleDataSource(databaseInfo.getJdbcUrl(), databaseInfo.getJdbcLoginname(), databaseInfo.getJdbcPassword());
                    dynamicRoutingDataSource.addDataSource(cdskey, dynamicDataSourceVO);
                }
                DynamicDataSourceContextHolder.push(cdskey);
            }
        }catch(Exception e){
            LOGGER.error("数据库连接异常{}",e);
            throw new BizException(GlobalEnum.DATABASE_CONNECT_FAILED);
        }
        
        List<String> tableList = new ArrayList<>();
        
        try{
            //查询数据库表
            if(tableCodes!=null && tableCodes.size()>0){
                for(String tableCode:tableCodes){
                    List<String> tlist = loadTableDao.get(resDTO.getDatabaseType()+"LoadDao").queryTables(tableCode,"0");
                    if(tlist!=null && tlist.size()>0){
                        for(String tx:tlist){
                            tx = tx.toUpperCase();
                            if(!tableList.contains(tx) && !tx.contains("$")){
                                tableList.add(tx);
                            }
                        }
                    }
                }
            }else{
                //查询所有表
                List<String> tlist = loadTableDao.get(resDTO.getDatabaseType()+"LoadDao").queryTables(null,"0");
                if(tlist!=null && tlist.size()>0){
                    for(String tx:tlist){
                        tx = tx.toUpperCase();
                        if(!tableList.contains(tx) && !tx.contains("$")){
                            tableList.add(tx);
                        }
                    }
                }
            }
            
            Map<String, List<ZlDatabaseTable>> tableColumns = new HashMap<>();
            
            if(tableList.size()>0){
                tableList.forEach(tableCode->{
                    if(("0".equals(reqData.getLoadType()) && !hasTableCodes.contains(tableCode)) 
                            || "1".equals(reqData.getLoadType())){
                        //查询字段
                        List<ZlDatabaseTable> clist = loadTableDao.get(resDTO.getDatabaseType()+"LoadDao").queryTableColumns(tableCode);
                        tableColumns.put(tableCode, clist);
                    }
                });
            }
            
            resDTO.setTableCodes(tableList);
            resDTO.setTableColumns(tableColumns);
        }catch(Exception e){
            LOGGER.error("数据库查询异常{}",e);
            throw new BizException(GlobalEnum.ERROR.getCode(),e.getMessage());
        }
        
        DynamicDataSourceContextHolder.clear();
        
        return resDTO;
    }
    
    
    @Override
    public void doUpdateDatabaseTableColumn(ReqDTO<ReqDatabaseTableAddDTO> reqInfo,ResDatabaseTableAddDTO resDTO) throws Exception{
        // TODO Auto-generated method stub
        ReqDatabaseTableAddDTO reqData = reqInfo.getReqData();
        
        Instant time = getSystemTime().getUtcTime();
        
        LOGGER.info("同步表开始");
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("databaseId", reqData.getDatabaseId());
        if("1".equals(reqData.getLoadType())){
            //删除字段
            databaseTableMapper.deleteByMap(paramMap);
        }else{
            resDTO.getTableColumns().forEach((tableCode,v)->{
                paramMap.put("tableCode", tableCode);
                //删除字段
                databaseTableMapper.deleteByMap(paramMap);
            });
        }
        
        resDTO.getTableColumns().forEach((tableCode,v)->{
            LOGGER.info("同步表>>{}",tableCode);
            for(ZlDatabaseTable record : v){
                initCreateInfo(record, reqInfo, time);
                record.setColumnJavaCode(StrUtil.toCamelCase(record.getColumnCode()));
                if(record.getColumnName()==null){
                    record.setColumnName(record.getColumnCode());
                }
                record.setColumnId(IdUtil.simpleUUID());
                record.setDatabaseId(reqData.getDatabaseId());
                record.setTableCode(tableCode);
                record.setOrderNum(0L);
                record.setDataStatus(AutocodeC.DataStatus.ENABLE.getCode());
                databaseTableMapper.insertSelective(record);
            }
        });
        LOGGER.info("同步表结束");
    }
    
    @Async
    @Override
    public void doUpdateDatabaseTableColumnAsync(ReqDTO<ReqDatabaseTableAddDTO> reqInfo,ResDatabaseTableAddDTO resDTO) throws Exception{
        doUpdateDatabaseTableColumn(reqInfo, resDTO);
    }

    @Override
    public ResDatabaseTableSqlQueryDTO querySqlResult(ReqDTO<ReqDatabaseTableSqlQueryDTO> reqInfo) throws Exception {
        // TODO Auto-generated method stub
        ReqDatabaseTableSqlQueryDTO reqData = reqInfo.getReqData();
        ResDatabaseTableSqlQueryDTO resDTO = new ResDatabaseTableSqlQueryDTO();
        
        PageQueryDTO page = new PageQueryDTO();
        page.setLimit(reqData.getLimit());
        page.setPage(reqData.getPage());
        pageHandle(page);//处理分页数据
        
        String cdskey = "dynamic-" + reqData.getDatabaseId();
        DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource)dynamicDataSource;
        if(dynamicRoutingDataSource.getCurrentDataSources().containsKey(cdskey)){
            DynamicDataSourceContextHolder.push(cdskey);
        }
        try{
            Page<Object> pageHp = PageHelper.startPage(page.getPage(), page.getLimit());
            List<MapString<String, Object>> result = onlineSqlMapper.selectResultByDiySql(reqData.getSqlStr());
            
            List<MapString<String, Object>> list =  new ArrayList<>();
            List<String> fields = new ArrayList<>();
            if(result!=null && result.size()>0){
                for(Entry<String, Object> x:result.get(0).entrySet()){
                    fields.add(x.getKey());
                }
                list = result;
            }
            
            resDTO.setList(list);
            resDTO.setTotal(pageHp.getTotal());
            resDTO.setFields(fields);
        }catch(Exception e){
            LOGGER.error("数据库查询异常{}",e);
            throw new BizException(GlobalEnum.ERROR.getMsg(),e.getMessage());
        }finally {
            DynamicDataSourceContextHolder.clear();
        }
        
        return resDTO;
    }
}